<?php
declare (strict_types=1);

namespace app\subscribe;

use app\Request;
use Swoole\Server;
use think\Container;
use think\swoole\Table;
use think\swoole\Websocket;

class WebSocketEvent
{
    protected $websocket = null;
    protected $server = null;
    protected $table = null;
    protected $u2fd = null;
    protected $fd2u = null;


    /**
     * WebSocketEvent constructor.
     * @param Server $server
     * @param Websocket $websocket
     * @param Container $container
     */
    public function __construct(Server $server, Websocket $websocket, Container $container)
    {
        $this->websocket = $websocket;
        $this->server = $server;
        $this->table = $container->get(Table::class);
        $this->u2fd = $this->table->u2fd;
        $this->fd2u = $this->table->fd2u;
    }

    public function onConnect(Request $request)
    {
        $uid = rand(100, 999);
        $this->table->u2fd->set((string)$uid, ['fd' => $this->websocket->getSender()]);
        $this->table->fd2u->set((string)$this->websocket->getSender(), ['uid' => $uid]);
        foreach ($this->table->u2fd as $row) {
            $this->server->push($row['fd'], json_encode(['msg' => 'online', 'uid' => $uid, 'online_count' => $this->u2fd->count(), 'fd' => $this->websocket->getSender()], 320));
        }
    }

    public function onClose()
    {
        $uid = $this->table->fd2u->get((string)$this->websocket->getSender(), 'uid');
        $this->table->u2fd->del((string)$uid);
        $this->table->fd2u->del((string)$this->websocket->getSender());
        foreach ($this->table->u2fd as $row) {
            $this->server->push($row['fd'], json_encode(['msg' => 'offline', 'uid' => $uid, 'online_count' => $this->u2fd->count(), 'fd' => $this->websocket->getSender()], 320));
        }
    }

    public function onPoint($event)
    {
        $toFd = $this->table->u2fd->get((string)$event['to'], 'fd');
        if ($toFd === false) {
            if (isset($event['api'])) {
                return 'offline';
            }
            $this->server->push($this->websocket->getSender(), $event['to'] . ' is not online');
        }
        if (isset($event['api'])) {
            $this->server->push($toFd, $this->assemblyData('point', ['sender' => $event['uid'] ?? 0, 'content' => $event['content']]));
        } else {
            $this->server->push($toFd, $this->assemblyData('point', ['sender' => $this->table->fd2u->get((string)$this->websocket->getSender(), 'uid'), 'content' => $event['content']]));
        }

    }

    public function onPing()
    {
        $this->server->push($this->websocket->getSender(), $this->assemblyData('pong', []));
    }

    protected function assemblyData(string $event, array $data, int $code = 0): string
    {
        return json_encode(['event' => $event, 'data' => $data, 'code' => $code], 320);
    }
}
